import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.StringTokenizer;

public class RO_ReadASCII {
	static String FILE_PATH = "../track1/trainIdx1.txt";
//	static String FILE_PATH = "../track1/validationIdx1.txt";
//	static String FILE_PATH = "../track1/testIdx1.txt";
	
	static String SUFFIX = "";
	static boolean HASH = false;
	static boolean SPLIT_OUTLIERS = false;
	static boolean INCLUDE_ITEM_SET = false;
	static boolean TAXONOMY = false;

	static User[] USER = new User[1000990];

	public static void main(String[] args) {
		readCommandline(args);
		tryRead();

		if (FILE_PATH.contains("train")) {
			sortUSER();
		}
		if(HASH){
			hashUSER();
		}
		
		if(SPLIT_OUTLIERS){
			splitOutliers();
		} else {
			writeSerialisedResult(FILE_PATH + ".ser" + SUFFIX, USER);
		}
		
		if(INCLUDE_ITEM_SET){
			RO_ConvertUSERtoITEM.SUFFIX = SUFFIX;
			RO_ConvertUSERtoITEM.TAXONOMY = TAXONOMY;
			RO_ConvertUSERtoITEM.go();
		}
	}
	
	static void readCommandline(String[] args) {
		for (int a = 0; a < args.length; a++) {
			if (args[a].equals("-i") || args[a].equals("-input")) {
				FILE_PATH = args[a+1];
				a++;
			} else if (args[a].equals("-s") || args[a].equals("-suffix")) {
				SUFFIX = args[a+1];
				a++;
			} else if (args[a].equals("-h") || args[a].equals("-hash")) {
				HASH = true;
			} else if (args[a].equals("-o") || args[a].equals("-outliers")) {
				SPLIT_OUTLIERS = true;
			} else if (args[a].equals("-t") || args[a].equals("-item")) {
				INCLUDE_ITEM_SET = true;
			} else if (args[a].equals("-a") || args[a].equals("-tax")) {
				TAXONOMY = true;
			} else {
				System.out.println("Unknown option: " + args[a]);
			}
		}
	}
	
	public static void go(String inputFile) {
		FILE_PATH = inputFile;
		tryRead();

		if (FILE_PATH.contains("train")) {
			sortUSER();
		}
		
		hashUSER();

		writeSerialisedResult(FILE_PATH + ".ser", USER);
	}

	static void tryRead() {
		System.out.println("tryRead: " + FILE_PATH);
		long time = System.currentTimeMillis();

		try {
			if (FILE_PATH.contains("test")) {
				readTest();
			} else {
				read();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println(System.currentTimeMillis() - time);
	}

	private static void read() throws Exception {
		File file = new File(FILE_PATH);
		BufferedReader bufRdr = new BufferedReader(new FileReader(file));
		String line = null;
		StringTokenizer st;
		int userID = -1;
		int ilen = -1;
		int itemIndex = -1;

		while ((line = bufRdr.readLine()) != null) {
			if (line.contains("|")) {
				st = new StringTokenizer(line, "|");
				userID = Integer.valueOf(st.nextToken());
				ilen = Integer.valueOf(st.nextToken());

				USER[userID] = new User(ilen);
				itemIndex = 0;
			} else {
				st = new StringTokenizer(line, "\t");
				int itemID = Integer.valueOf(st.nextToken());
				byte vote = Byte.valueOf(st.nextToken());
				USER[userID].items[itemIndex] = itemID;
				USER[userID].votes[itemIndex] = vote;
				USER[userID].mean += (double) vote;
				itemIndex++;
			}
		}
		bufRdr.close();
	}

	private static void readTest() throws Exception {
		File file = new File(FILE_PATH);
		BufferedReader bufRdr = new BufferedReader(new FileReader(file));
		String line = null;
		StringTokenizer st;
		int userID = -1;
		int ilen = -1;
		int itemIndex = -1;

		while ((line = bufRdr.readLine()) != null) {
			if (line.contains("|")) {
				st = new StringTokenizer(line, "|");
				userID = Integer.valueOf(st.nextToken());
				ilen = Integer.valueOf(st.nextToken());

				USER[userID] = new User(ilen);
				itemIndex = 0;
			} else {
				st = new StringTokenizer(line, "\t");
				int itemID = Integer.valueOf(st.nextToken());
				USER[userID].items[itemIndex] = itemID;
				USER[userID].votes[itemIndex] = 0;
				itemIndex++;
			}
		}
		bufRdr.close();
	}

	static void sortUSER() {
		System.out.println("sortUSER");
		long time = System.currentTimeMillis();

		for (User user : USER) {
			user.sort();
			user.mean = user.mean / user.ilen;
		}

		System.out.println(System.currentTimeMillis() - time);
	}
	
	static void hashUSER(){
		System.out.println("hashUSER");
		long time = System.currentTimeMillis();
		
		for (User user : USER) {
			user.hash();
		}
		
		System.out.println(System.currentTimeMillis() - time);
		
	}

	static void splitOutliers(){
		User[] outliers = new User[1000990];
		User[] normal = new User[1000990];
		User user;
		
		System.out.println("splitOutliers");
		long time = System.currentTimeMillis();
		
		for (int i=0; i<USER.length; i++) {
			user = USER[i];
			if(user.ilen>31250){
				outliers[i] = user;
			} else{
				normal[i] = user;
			}
		}
		
		writeSerialisedResult(FILE_PATH + ".ser.normal", normal);
		writeSerialisedResult(FILE_PATH + ".ser.outlier", outliers);
		
		System.out.println(System.currentTimeMillis() - time);
	}
	
	private static void writeSerialisedResult(String outputFile, Serializable object) {
		System.out.println("writeSerialisedResult: " + outputFile);
		long time = System.currentTimeMillis();

		try {
			OutputStream file = new FileOutputStream(outputFile);
			OutputStream buffer = new BufferedOutputStream(file);
			ObjectOutput output = new ObjectOutputStream(buffer);
			try {
				output.writeObject(object);
			} finally {
				output.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println(System.currentTimeMillis() - time);
	}
}
